package com.unknown.communication;

import com.unknown.communication.entity.Member;
import com.unknown.communication.entity.Message;
import com.unknown.communication.entity.Pool;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class AndroidBus {
    private static AndroidBus androidBus;
    private List<Member> members;
    private List<Pool> pools; //to be received pools

    private AndroidBus() {
        members = new ArrayList<>();
        pools = new LinkedList<>();
    }

    public static void init() {
        androidBus = new AndroidBus();
    }

    public static AndroidBus getInstance() {
        return androidBus;
    }

    public void register(Member member) {
        members.add(member);
        sendUnreceivedMessage(member);
    }

    public void unregister(Member member) {
        members.remove(member);
        removeFromPool(member);
    }

    public void send(Message message) {
        Member member = findReceiver(message);
        if (member == null) {
            pools.add(new Pool(message));
        } else {
            sendTo(member, message);
        }
    }

    private void sendUnreceivedMessage(Member member) {
        List<Message> messages = findUnreceivedMessage(member);
        if (messages == null) {
            return;
        }
        sendTo(member, messages);
    }

    private Member findReceiver(Message message) {
        for (Member member : members) {
            if (member.getClass() == message.getReceiver()) {
                return member;
            }
        }
        return null;
    }

    private List<Message> findUnreceivedMessage(Member member) {
        for (Pool pool : pools) {
            if (pool.getMember().equals(member.getClass())) {
                return pool.getMessages();
            }
        }
        return null;
    }

    private void removeFromPool(final Member member) {
        pools.forEach(pool -> {
            if (pool.getMember().equals(member.getClass())) {
                pools.remove(pool);
            }
        });
    }

    private void removeFromPool(Message message) {
        pools.forEach(pool -> {
            if (pool.getMember().getClass().equals(message.getReceiver())) {
                pool.getMessages().remove(message);
            }
        });
    }

    private void sendTo(Member member, List<Message> messages) {
        for (Message message : messages) {
            sendTo(member, message);
        }
    }

    private void sendTo(Member member, Message message) {
        member.onReceived(message);
        removeFromPool(message);
    }
}
